package com.itheima.pinda.authority.biz.service.auth.impl;

import com.itheima.pinda.authority.biz.service.auth.ValidateCodeService;
import com.itheima.pinda.common.constant.CacheKey;
import com.itheima.pinda.exception.BizException;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import lombok.extern.slf4j.Slf4j;
import net.oschina.j2cache.CacheChannel;
import net.oschina.j2cache.CacheObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author llhuang10
 * @date 2021/8/27 10:00
 */
@Slf4j
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {

    /**
     * 通过当前对象可以操作j2cache缓存
     */
    @Resource
    private CacheChannel cacheChannel;


    /**
     * 生成验证码, 并写入到res的输出流中, 同时要将验证码进行缓存
     *
     * @param key 前端系统随机生成的key
     * @param res response
     */
    @Override
    public void create(String key, HttpServletResponse res) {
        if (StringUtils.isBlank(key)) {
            throw BizException.validFail("验证码key不能为空");
        }

        Captcha captcha = new SpecCaptcha();
        // 本次产生的验证码
        String text = captcha.text();
        // 将生成的验证码, 缓存起来  key = captcha:{key}  value = {captcha.text()}
        cacheChannel.set(CacheKey.CAPTCHA, key, text);
        // todo 如何区分不同用户的验证码, 使用前端传过来的一个key [前端随机生成]

        // 将生成的验证码图片通过输出流写回客户端浏览器页面
        try (OutputStream outputStream = res.getOutputStream()) {
            res.reset();
            res.setContentType(MediaType.IMAGE_PNG_VALUE);
            //
            res.addHeader(HttpHeaders.PRAGMA, "No-cache");
            res.addHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
            res.setDateHeader(HttpHeaders.EXPIRES, 0L);

            captcha.out(outputStream);
        } catch (IOException ex) {
            log.error("ex: {}", ex.getMessage(), ex);
        }
    }

    /**
     * 校验验证码是否正确
     *
     * @param code 验证码
     * @param key  验证码key
     * @return
     */
    @Override
    public boolean check(String code, String key) {
        if (StringUtils.isBlank(key)) {
            /**
             * 这种手抛出的异常, 都会返回给前端页面[ 返回的数据有 msg:验证码key不能为空, isSuccess: false, isError: true]
             * 也会在控制台打印出
             */
            throw BizException.validFail("验证码key不能为空");
        }
        // 根据key从缓存中获取保存的验证码
        CacheObject cacheObject = cacheChannel.get(CacheKey.CAPTCHA, key);
        if (cacheObject.getValue() == null) {
            throw BizException.validFail("验证码已经过期");
        }
        String codeInCache = (String) cacheObject.getValue();
        if (!codeInCache.equalsIgnoreCase(code)) {
            throw BizException.validFail("验证码错误");
        }
        // 验证成功后, 立即清除这个缓存中的验证码
        cacheChannel.evict(CacheKey.CAPTCHA, key);
        return true;
    }

}
